Repository navigation
perf: 부하테스트(2026-10)로 찾은 오류·과한 트랜잭션 수정 - #324
Merged
Merged
Conversation
데이터소스를 감싸 커넥션 대여·커밋·SQL 문장을 기록하는 시험 전용 SqlRecorder 와, 로그인·리프레시·템플릿 초안· 생성·홈의 DB 작업을 출력하는 RequestDbProfileIT. 부하테스트(2026-10)에서 로그인·생성이 과한지 보려고 만들었다. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
인증된 요청마다 user_activity upsert 가 돌아 GET 하나가 곧 DB 쓰기 하나·커넥션 대여 하나였다. 값이 날짜라 같은 날 반복은 결과가 같으므로 태스크마다 오늘 기록 여부를 기억하고 건너뛴다. 로그인·가입은 touchNow 로 반드시 쓴다(같은 날 앞선 기록이 탈퇴 상태라 무시됐을 수 있다). 로그인은 저장 전후로 두 번 쓰던 것을 저장 뒤 한 번으로. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
배포·스케일아웃마다 워밍업이 Unable to connect to Redis 로 실패해 회로가 열리고 5분 스윕까지 탐색이 SQL 폴백으로 돌았다(stg·prod 모두). 컨테이너에서 연결+PING 은 7ms 라 네트워크 문제가 아니라 0.5 vCPU 에서 막 뜬 JVM 의 첫 핸드셰이크 지연이다. 워밍업 전에 PING 을 최대 5회(2·4·6·8초 간격) 시도하고, 실패 원인은 감싼 예외가 아니라 맨 안쪽 원인까지 남긴다. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
draft() 가 @transactional 이라 시작 시점에 커넥션을 잡고 LLM 응답(수 초, 재시도·폴백 시 수십 초)까지 쥐고 있었다. 태스크 풀 15개 중 동시 AI 초안 수만큼이 묶인다. DB 작업은 등급 조회·초안 저장 둘뿐이라 각자 리포지토리 트랜잭션으로 충분하다. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
같은 사용자의 sync 가 겹치면(재전송·백로그, 빈도 제한기가 태스크마다 메모리에 있어 두 태스크로 나뉘면 못 막는다) 세션 갱신·신호 INSERT IGNORE·판정 갱신을 하는 긴 트랜잭션이 서로의 잠금을 잡아 한쪽이 데드락으로 졌다 — 부하테스트 피크 5xx 11건 전부. 봉투 검증·빈도 제한은 한 번만 하고 트랜잭션 본문만 최대 3회 다시 돈다. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
stg·prod 접속 주소(env)가 기본 주소를 통째로 덮어 rewriteBatchedStatements 가 빠져 있었다 — 신호 일괄 적재가 행마다 따로 나갔다. 프로파일에서 드라이버가 CPU 의 16% 였다. 문장 캐시·세션 상태 로컬 관리·autocommit 왕복 생략을 hikari.data-source-properties 로 둬 주소와 상관없이 적용한다. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@scheduled 54개가 기본 스레드 1개를 나눠 써서 긴 작업 뒤에 다른 작업이 밀렸다. 밀린 cron 작업은 다른 태스크의 ShedLock 최소 잠금이 풀린 뒤에 시작해 같은 날 중복 실행됐다(00:40 일별 집계가 태스크 3대에서 각각 00:40·00:41·00:43). SCHEDULER_POOL_SIZE 로 조정한다. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
한 번 실행에 200건만 전환하고 끝나서, 시작일이 자정에 몰린 방 4,870건이 모두 ACTIVE 가 되기까지 22분 걸렸다. 그동안 오늘 시작인 방이 「시작 전」으로 보이고 인증이 평가되지 않는다. 200건씩 한 트랜잭션으로 끊어 남은 것이 없을 때까지(실행당 최대 4분, 락 10분 안) 돈다. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
500ms 는 앱 CPU 가 포화되면 Redis 가 한가해도(엔진 CPU 5%) 넘겼고, 3번 연속이면 그 태스크의 탐색 전체가 30초간 503 이었다(가입 몰림 시드에서 145건). 진짜 장애는 2초로도 충분히 빨리 걸린다. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
피크(350 RPS)에서 100% 기록은 에이전트 스팬 큐(2048)를 넘쳐 스팬을 버리고 기록 요금도 하루 ~$150 꼴이 된다. 초당 10건 예약분은 그대로라 평소 트래픽은 전부 남는다. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
먼저 세고 나서 락을 기다리면 그 첫 SELECT 에 REPEATABLE READ 스냅샷이 고정돼, 기다리는 동안 커밋된 가입·판정을 못 본 채 앞서 끝난 재계산을 옛 값으로 덮었다. 2배 피크 부하테스트에서 5분 보정이 43건을 고친 원인. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
실사용 비율의 피크(DAU 1만·동시 500), 2배 스트레스, 한계점, 장시간, AI 초안 시나리오와 API별 SLO 임계값. 준비(stg 로그인 우회·prod 동일 조건)·함정은 README. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Test Coverage
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
요약
stg 를 prod 와 같은 조건(0.5 vCPU/2GB·2~4대·Hikari 15·RDS Multi-AZ·DB TLS)으로 올려 RuleUp 사용 패턴(DAU 1만·동시 500) 기준으로 부하·성능 시험을 돌리며 찾은 오류·과한 트랜잭션을 고친다. 결과·권고는 노션 「부하테스트 및 성능개선」.
커밋 (작업 단위)
SqlRecorder·RequestDbProfileITuser_activityupsert → 하루 1번, 로그인 중복 기록 제거draft()의@Transactional제거rewriteBatchedStatements·문장 캐시 등ruleup-api100% → 예약 10/s + 10%refresh()가 방 행을 잠근 뒤 센다infra/loadtest결과 (피크 시나리오, 같은 데이터에서 연달아)
배포 후 따로 할 일 (이 PR 밖)
enable_tracing.py의 규칙만 적용한다.테스트
./gradlew test전체 통과ChallengeStatsProjectionIT$ConcurrentRefresh(수정 전 실패 확인),VerificationSyncDeadlockRetryIT,ChallengeLifecycleBatchIT#activatesBeyondOneChunkInOneRun,ExploreWarmupRetryTest🤖 Generated with Claude Code